package edu.ucla.cs.typecast.app.news;

import java.io.*;
import java.util.regex.*;

public class ScriptParser {
	protected String getPattern() {
		// For "wait":
		// $9 - wait time in ms

		// For "send":
		// $2 - class name
		// $4 - content [optional]
		// $6 - rate [optional]
		// $8 - duration [optional]

		// For both:
		// $11 - comment

		final String $pString = "([^\\s]+|\".*?\")";

		final String pContentClause = "(\\s+content\\s+" + $pString + ")?";
		final String pRateClause = "(\\s+rate\\s+(\\d+))?";
		final String pDurationClause = "(\\s+duration\\s+(\\d+))?";
		final String pClassClause = "\\s+class\\s+([\\w\\.]+)";

		final String pSendClause = "send" + pClassClause + pContentClause
				+ pRateClause + pDurationClause;
		final String pWaitClause = "wait\\s+(\\d+)";

		final String pCommand = "(" + pSendClause + "|" + pWaitClause + ")";
		final String pComment = "#(.*)";

		final String pLine = pCommand + "?\\s*(" + pComment + ")?";

		return pLine;
	}

	public void parse(Reader r, boolean ignoreError) throws IOException,
			ClassNotFoundException {
		BufferedReader br = (r instanceof BufferedReader) ? (BufferedReader) r
				: new BufferedReader(r);

		int lineNum = 0;
		while (true) {
			String line = br.readLine();
			if (line == null)
				break;

			lineNum++;

			parseLine(line, lineNum, ignoreError);
		}
	}

	public void parse(String s, boolean ignoreError) throws IOException,
			ClassNotFoundException {
		parse(new StringReader(s), false);
	}

	protected void parseLine(String line, int lineNum, boolean ignoreError)
			throws ClassNotFoundException {
		Matcher matcher = Pattern.compile(getPattern(),
				Pattern.CASE_INSENSITIVE).matcher(line.trim());
		if (matcher.matches()) {
			if (matcher.group(9) != null) {
				waitFor(Integer.parseInt(matcher.group(9)));
			}
			if (matcher.group(2) != null) {
				Class cls = Class.forName(matcher.group(2));
				String content = stripQuote(matcher.group(4));
				Integer rate = (matcher.group(6) != null) ? Integer
						.parseInt(matcher.group(6)) : null;
				Integer duration = (matcher.group(8) != null) ? Integer
						.parseInt(matcher.group(8)) : null;
				send(cls, content, rate, duration);
			}
		} else {
			if (!ignoreError)
				throw new ScriptParseException(line, lineNum);
		}

	}

	protected String stripQuote(String str) {
		if (str != null && str.length() >= 2 && str.startsWith("\"")
				&& str.endsWith("\"")) {
			return str.substring(1, str.length() - 1);
		} else {
			return str;
		}
	}

	protected void send(Class cls, String content, Integer rate,
			Integer duration) {
		// To be overrided
	}

	protected void waitFor(int time) {
		try {
			Thread.sleep(time);
		} catch (InterruptedException e) {

		}
	}
}
